#include "RenzoPrecompiled.h"
#include "RenzoPolygonGroup.h"
#include "RenzoRenderSystem.h"
#include "RenzoVertexBuffer.h"
#include "RenzoAnimatorKeyFrame.h"

namespace Renzo
{
PolygonGroup::PolygonGroup(void)
: texture(NULL), material(NULL)
{
	animator = NULL;
}

Object* PolygonGroup::create() {
	return new PolygonGroup;
}

PolygonGroup::~PolygonGroup(void)
{
}

void PolygonGroup::addVertex(Vertex* v) {
	vertices.push_back(*v);
}

void PolygonGroup::addFace(Face* f) {
	faces.push_back(*f);
}

const Texture* PolygonGroup::getTexture() const {
	return texture;
}

void PolygonGroup::setTexture(Texture* t) {
	this->texture = t;
}

const Material* PolygonGroup::getMaterial() const {
	return material;
}

void PolygonGroup::setMaterial(Material* m) {
	this->material = m;
}

BoundingBox* PolygonGroup::getBoundingBoxAABB() {
	bb.min = INF_MAX;
	bb.max = INF_MIN;
	for (int i = 0; i < vertices.size(); ++i) {
		bb.min = rzMin3(bb.min, vertices[i].position);
		bb.max = rzMax3(bb.max, vertices[i].position);
	}

	bb.center = (bb.min + bb.max) * 0.5f;
	bb.dim = bb.max - bb.min;
	bb.radius = bb.dim.length() * 0.5f;

	return &bb;
}

void PolygonGroup::transform(const Matrix4& mat) {
	matTransform = mat;
	/*
	VertexList::iterator i;	
	for (i = vertices.begin(); i != vertices.end(); ++i) {
		Vertex* v = &(*i);
		v->position = rzPointTransform(mat, v->position);
	}*/
}

void PolygonGroup::update(int delta) {
	// animation
	animator->update(delta);
}

void PolygonGroup::render() {
	// pass polygons down to vertex buffer
	// MD2 mesh is highly inefficient as vertices needs to be interpolated and pass to graphic hardware memory every frame!

	int i, j;
	
	//int offFrame = curFrame * header->numFaces * 3;
	//int nextFrame = (curFrame + 1) % header->numFrames;	
	//int offNextFrame = nextFrame * header->numFaces * 3;
	int offFrame = 0;
	int offNextFrame = 0;
	int nextFrame = 0;
	int nbFacesPerFrame = 0;

	if (animator) { // if animation is enabled
		AnimatorKeyFrame* animatorKey = dynamic_cast<AnimatorKeyFrame*>(animator);
		int curFrame = animatorKey->getCurrentFrame();
		nbFacesPerFrame = animatorKey->getFacesPerFrame();
		offFrame = curFrame * nbFacesPerFrame * 3; 
		nextFrame = (curFrame + 1) % animatorKey->getFrameCount();
		offNextFrame = nextFrame * nbFacesPerFrame * 3;
	}
			
		VertexBuffer* vbuf = Renzoderer::instance()->getActiveRenderSystem()->getVertexBuffer();
		
			//
			// insert a new mesh
			//
			vbuf->beginObject();

			// add a new texture object to the buffer
			vbuf->beginTexture();			
			vbuf->add(0, texture); 
			vbuf->endTexture();

			// copy vertices of the current frame	
			Vertex v, v1, v2;
			//float alpha = min(1.0f, (float)curTimeElapsed / frameTimeElapsed); // linear interpolation 
			float alpha = 1.0f;			
			//for (i = 0; i < header->numFaces * 3; ++i) {
			//for (i = 0; i < vertices.size(); ++i) {
			for (i = 0; i < nbFacesPerFrame * 3; ++i) {
				v1 = vertices[offFrame + i]; // copy to a new vertex

				// interpolate between frames
				v2 = vertices[offNextFrame + i];
				v.position = v1.position + (v2.position - v1.position) * alpha;

				// transform
				v.position = rzPointTransform(matTransform, v.position);
				// copy remaining data 
				//memcpy(v.texCoords, v1.texCoords, sizeof(v.texCoords));
				memcpy(v.texCoords, v1.texCoords, sizeof(Float4) * 8);
				//v.color; 
				//v.normal;
				vbuf->add(&v);
				//vbuf->add(&vertices[offFrame + i]);

				//printf("%f %f %f\n", vertices[offFrame + i].position.x, vertices[offFrame + i].position.y, vertices[offFrame + i].position.z);
			
				
			}
			// make indices
			// hack: 
			//header->numFaces = 500;
			//Face f;
			//for (i = 0; i < header->numFaces; i++) {
			//for (i = 0; i < faces.size(); i++) {
			for (i = 0; i < nbFacesPerFrame; i++) {
				/*
				f.indices[0] = faces[i].indexVertex[0];
				f.indices[1] = faces[i].indexVertex[1];
				f.indices[2] = faces[i].indexVertex[2];
				*/

				//
				// Front face in MD2 model is CW. 
				// Flip the order of the vertices to make it CCW, which is front face in OpenGL.
				//
				//f.indices[0] = 3 * i;
				//f.indices[2] = 3 * i + 1;
				//f.indices[1] = 3 * i + 2;


				//printf("%d %d %d\n", f.indices[0], f.indices[1], f.indices[2]);
				/*
				printf("%d %d %d\n", faces[i].indexVertex[0], faces[i].indexVertex[1], faces[i].indexVertex[2]);
				if (f.indices[0] < 0 || f.indices[1] < 0 || f.indices[2] < 0) {
					rzSevere(1, "MD2 indices less than zero.\n");
				}
				if (f.indices[0] > header->numVertices || f.indices[1] > header->numVertices || f.indices[2] > header->numVertices) {
					printf("%d %d %d\n", f.indices[0], f.indices[1], f.indices[2]);
					printf("%d %d %d\n", faces[i].indexVertex[0], faces[i].indexVertex[1], faces[i].indexVertex[2]);
					rzSevere(3, "MD2 indices >= numVertices.\n");
				}
				*/
				vbuf->add(&faces[i]);
			}
			vbuf->endObject();
		
		/*
			for (j = 0; j < 3; j++) {
				
				glTexCoord2f(
					fTextures[faces[i].indexTexture[j]].x, 
					fTextures[faces[i].indexTexture[j]].y 
				);
				

				curX = vertices[offFrame + faces[i].indexVertex[j]]->position.x;
				curY = vertices[offFrame + faces[i].indexVertex[j]]->position.y; 
				curZ = vertices[offFrame + faces[i].indexVertex[j]]->position.z;
				
				nextX = vertices[offNextFrame + faces[i].indexVertex[j]]->position.x;
				nextY = vertices[offNextFrame + faces[i].indexVertex[j]]->position.y; 
				nextZ = vertices[offNextFrame + faces[i].indexVertex[j]]->position.z;
				
				x = curX + (nextX - curX) * curTimeElapsed / frameTimeElapsed;
				y = curY + (nextY - curY) * curTimeElapsed / frameTimeElapsed;
				z = curZ + (nextZ - curZ) * curTimeElapsed / frameTimeElapsed;

				
				v->position.x = x;
				v->position.y = y;
				v->position.z = z;
				// pass this vertex to hardware graphic memory
				vbuf->add(v);
				
				glVertex3f(
					x, y, z
				);
			}
		}
		delete v;
		//glEnd();

	
	/* restore to default face order (counter clock-wise) */
	//glPopAttrib();
}

}
